(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
        typeof define === 'function' && define.amd ? define(factory) :
            (factory());
}(this, (function () { 'use strict';

    function createCommonjsModule(fn, module) {
        return module = { exports: {} }, fn(module, module.exports), module.exports;
    }

    var eventemitter3 = createCommonjsModule(function (module) {
        var has = Object.prototype.hasOwnProperty,
            prefix = '~';

        /**
         * Constructor to create a storage for our `EE` objects.
         * An `Events` instance is a plain object whose properties are event names.
         *
         * @constructor
         * @private
         */
        function Events() {}

//
// We try to not inherit from `Object.prototype`. In some engines creating an
// instance in this way is faster than calling `Object.create(null)` directly.
// If `Object.create(null)` is not supported we prefix the event names with a
// character to make sure that the built-in object properties are not
// overridden or used as an attack vector.
//
        if (Object.create) {
            Events.prototype = Object.create(null);

            //
            // This hack is needed because the `__proto__` property is still inherited in
            // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
            //
            if (!new Events().__proto__) prefix = false;
        }

        /**
         * Representation of a single event listener.
         *
         * @param {Function} fn The listener function.
         * @param {*} context The context to invoke the listener with.
         * @param {Boolean} [once=false] Specify if the listener is a one-time listener.
         * @constructor
         * @private
         */
        function EE(fn, context, once) {
            this.fn = fn;
            this.context = context;
            this.once = once || false;
        }

        /**
         * Add a listener for a given event.
         *
         * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
         * @param {(String|Symbol)} event The event name.
         * @param {Function} fn The listener function.
         * @param {*} context The context to invoke the listener with.
         * @param {Boolean} once Specify if the listener is a one-time listener.
         * @returns {EventEmitter}
         * @private
         */
        function addListener(emitter, event, fn, context, once) {
            if (typeof fn !== 'function') {
                throw new TypeError('The listener must be a function');
            }

            var listener = new EE(fn, context || emitter, once),
                evt = prefix ? prefix + event : event;

            if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);else emitter._events[evt] = [emitter._events[evt], listener];

            return emitter;
        }

        /**
         * Clear event by name.
         *
         * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
         * @param {(String|Symbol)} evt The Event name.
         * @private
         */
        function clearEvent(emitter, evt) {
            if (--emitter._eventsCount === 0) emitter._events = new Events();else delete emitter._events[evt];
        }

        /**
         * Minimal `EventEmitter` interface that is molded against the Node.js
         * `EventEmitter` interface.
         *
         * @constructor
         * @public
         */
        function EventEmitter() {
            this._events = new Events();
            this._eventsCount = 0;
        }

        /**
         * Return an array listing the events for which the emitter has registered
         * listeners.
         *
         * @returns {Array}
         * @public
         */
        EventEmitter.prototype.eventNames = function eventNames() {
            var names = [],
                events,
                name;

            if (this._eventsCount === 0) return names;

            for (name in events = this._events) {
                if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
            }

            if (Object.getOwnPropertySymbols) {
                return names.concat(Object.getOwnPropertySymbols(events));
            }

            return names;
        };

        /**
         * Return the listeners registered for a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @returns {Array} The registered listeners.
         * @public
         */
        EventEmitter.prototype.listeners = function listeners(event) {
            var evt = prefix ? prefix + event : event,
                handlers = this._events[evt];

            if (!handlers) return [];
            if (handlers.fn) return [handlers.fn];

            for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
                ee[i] = handlers[i].fn;
            }

            return ee;
        };

        /**
         * Return the number of listeners listening to a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @returns {Number} The number of listeners.
         * @public
         */
        EventEmitter.prototype.listenerCount = function listenerCount(event) {
            var evt = prefix ? prefix + event : event,
                listeners = this._events[evt];

            if (!listeners) return 0;
            if (listeners.fn) return 1;
            return listeners.length;
        };

        /**
         * Calls each of the listeners registered for a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @returns {Boolean} `true` if the event had listeners, else `false`.
         * @public
         */
        EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
            var evt = prefix ? prefix + event : event;

            if (!this._events[evt]) return false;

            var listeners = this._events[evt],
                len = arguments.length,
                args,
                i;

            if (listeners.fn) {
                if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);

                switch (len) {
                    case 1:
                        return listeners.fn.call(listeners.context), true;
                    case 2:
                        return listeners.fn.call(listeners.context, a1), true;
                    case 3:
                        return listeners.fn.call(listeners.context, a1, a2), true;
                    case 4:
                        return listeners.fn.call(listeners.context, a1, a2, a3), true;
                    case 5:
                        return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
                    case 6:
                        return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
                }

                for (i = 1, args = new Array(len - 1); i < len; i++) {
                    args[i - 1] = arguments[i];
                }

                listeners.fn.apply(listeners.context, args);
            } else {
                var length = listeners.length,
                    j;

                for (i = 0; i < length; i++) {
                    if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);

                    switch (len) {
                        case 1:
                            listeners[i].fn.call(listeners[i].context);break;
                        case 2:
                            listeners[i].fn.call(listeners[i].context, a1);break;
                        case 3:
                            listeners[i].fn.call(listeners[i].context, a1, a2);break;
                        case 4:
                            listeners[i].fn.call(listeners[i].context, a1, a2, a3);break;
                        default:
                            if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
                                args[j - 1] = arguments[j];
                            }

                            listeners[i].fn.apply(listeners[i].context, args);
                    }
                }
            }

            return true;
        };

        /**
         * Add a listener for a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @param {Function} fn The listener function.
         * @param {*} [context=this] The context to invoke the listener with.
         * @returns {EventEmitter} `this`.
         * @public
         */
        EventEmitter.prototype.on = function on(event, fn, context) {
            return addListener(this, event, fn, context, false);
        };

        /**
         * Add a one-time listener for a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @param {Function} fn The listener function.
         * @param {*} [context=this] The context to invoke the listener with.
         * @returns {EventEmitter} `this`.
         * @public
         */
        EventEmitter.prototype.once = function once(event, fn, context) {
            return addListener(this, event, fn, context, true);
        };

        /**
         * Remove the listeners of a given event.
         *
         * @param {(String|Symbol)} event The event name.
         * @param {Function} fn Only remove the listeners that match this function.
         * @param {*} context Only remove the listeners that have this context.
         * @param {Boolean} once Only remove one-time listeners.
         * @returns {EventEmitter} `this`.
         * @public
         */
        EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
            var evt = prefix ? prefix + event : event;

            if (!this._events[evt]) return this;
            if (!fn) {
                clearEvent(this, evt);
                return this;
            }

            var listeners = this._events[evt];

            if (listeners.fn) {
                if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
                    clearEvent(this, evt);
                }
            } else {
                for (var i = 0, events = [], length = listeners.length; i < length; i++) {
                    if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
                        events.push(listeners[i]);
                    }
                }

                //
                // Reset the array, or remove it completely if we have no more listeners.
                //
                if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;else clearEvent(this, evt);
            }

            return this;
        };

        /**
         * Remove all listeners, or those of the specified event.
         *
         * @param {(String|Symbol)} [event] The event name.
         * @returns {EventEmitter} `this`.
         * @public
         */
        EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
            var evt;

            if (event) {
                evt = prefix ? prefix + event : event;
                if (this._events[evt]) clearEvent(this, evt);
            } else {
                this._events = new Events();
                this._eventsCount = 0;
            }

            return this;
        };

//
// Alias methods names because people roll like that.
//
        EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
        EventEmitter.prototype.addListener = EventEmitter.prototype.on;

//
// Expose the prefix.
//
        EventEmitter.prefixed = prefix;

//
// Allow `EventEmitter` to be imported as module namespace.
//
        EventEmitter.EventEmitter = EventEmitter;

//
// Expose the module.
//
        {
            module.exports = EventEmitter;
        }
    });

    var containers = []; // will store container HTMLElement references
    var styleElements = []; // will store {prepend: HTMLElement, append: HTMLElement}

    var usage = 'insert-css: You need to provide a CSS string. Usage: insertCss(cssString[, options]).';

    function insertCss(css, options) {
        options = options || {};

        if (css === undefined) {
            throw new Error(usage);
        }

        var position = options.prepend === true ? 'prepend' : 'append';
        var container = options.container !== undefined ? options.container : document.querySelector('head');
        var containerId = containers.indexOf(container);

        // first time we see this container, create the necessary entries
        if (containerId === -1) {
            containerId = containers.push(container) - 1;
            styleElements[containerId] = {};
        }

        // try to get the correponding container + position styleElement, create it otherwise
        var styleElement;

        if (styleElements[containerId] !== undefined && styleElements[containerId][position] !== undefined) {
            styleElement = styleElements[containerId][position];
        } else {
            styleElement = styleElements[containerId][position] = createStyleElement();

            if (position === 'prepend') {
                container.insertBefore(styleElement, container.childNodes[0]);
            } else {
                container.appendChild(styleElement);
            }
        }

        // strip potential UTF-8 BOM if css was read from a file
        if (css.charCodeAt(0) === 0xFEFF) {
            css = css.substr(1, css.length);
        }

        // actually add the stylesheet
        if (styleElement.styleSheet) {
            styleElement.styleSheet.cssText += css;
        } else {
            styleElement.textContent += css;
        }

        return styleElement;
    }

    function createStyleElement() {
        var styleElement = document.createElement('style');
        styleElement.setAttribute('type', 'text/css');
        return styleElement;
    }

    var insertCss_1 = insertCss;
    var insertCss_2 = insertCss;

    insertCss_1.insertCss = insertCss_2;

    var componentQuery = createCommonjsModule(function (module, exports) {
        function one(selector, el) {
            return el.querySelector(selector);
        }

        exports = module.exports = function (selector, el) {
            el = el || document;
            return one(selector, el);
        };

        exports.all = function (selector, el) {
            el = el || document;
            return el.querySelectorAll(selector);
        };

        exports.engine = function (obj) {
            if (!obj.one) throw new Error('.one callback required');
            if (!obj.all) throw new Error('.all callback required');
            one = obj.one;
            exports.all = obj.all;
            return exports;
        };
    });

    var componentQuery_1 = componentQuery.all;
    var componentQuery_2 = componentQuery.engine;

    /**
     * Module dependencies.
     */

    try {
        var query$1 = componentQuery;
    } catch (err) {
        var query$1 = componentQuery;
    }

    /**
     * Element prototype.
     */

    var proto = Element.prototype;

    /**
     * Vendor function.
     */

    var vendor = proto.matches || proto.webkitMatchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector;

    /**
     * Expose `match()`.
     */

    var componentMatchesSelector = match;

    /**
     * Match `el` to `selector`.
     *
     * @param {Element} el
     * @param {String} selector
     * @return {Boolean}
     * @api public
     */

    function match(el, selector) {
        if (!el || el.nodeType !== 1) return false;
        if (vendor) return vendor.call(el, selector);
        var nodes = query$1.all(selector, el.parentNode);
        for (var i = 0; i < nodes.length; ++i) {
            if (nodes[i] == el) return true;
        }
        return false;
    }

    /**
     * Module Dependencies
     */

    try {
        var matches = componentMatchesSelector;
    } catch (err) {
        var matches = componentMatchesSelector;
    }

    /**
     * Export `closest`
     */

    var componentClosest = closest;

    /**
     * Closest
     *
     * @param {Element} el
     * @param {String} selector
     * @param {Element} scope (optional)
     */

    function closest(el, selector, scope) {
        scope = scope || document.documentElement;

        // walk up the dom
        while (el && el !== scope) {
            if (matches(el, selector)) return el;
            el = el.parentNode;
        }

        // check scope for match
        return matches(el, selector) ? el : null;
    }

    var classCallCheck = function (instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    };

    var createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    function install(hook, vm) {
        var bus = new eventemitter3();

        hook.init(function () {
            css();
        });

        hook.afterEach(function (html, next) {
            bus.once('done', function () {
                next(render(html, pagination(vm)));
            });
        });

        hook.doneEach(function () {
            bus.emit('done');
        });
    }

    function toArray(elements) {
        return Array.prototype.slice.call(elements);
    }
    function findHyperlink(li) {
        return toArray(li.children).find(function (child) {
            return child.tagName && child.tagName.toUpperCase() === 'A';
        });
    }

    function pagination(vm) {
        try {
            var path = vm.route.path;
            var all = toArray(componentQuery.all('.sidebar li a')).filter(function (element) {
                return !componentMatchesSelector(element, '.section-link');
            });
            var active = all.find(function (item) {
                return item.getAttribute('href') === '#' + path;
            });
            var group = toArray((componentClosest(active, 'ul') || {}).children).filter(function (element) {
                return element.tagName.toUpperCase() === 'LI';
            });
            var index = group.findIndex(function (item) {
                var hyperlink = findHyperlink(item);
                return hyperlink && hyperlink.getAttribute('href') === '#' + path;
            });
            return {
                prev: new Link(group[index - 1]).toJSON(),
                next: new Link(group[index + 1]).toJSON()
            };
        } catch (error) {
            return {};
        }
    }

    var Link = function () {
        function Link(element) {
            classCallCheck(this, Link);

            if (!element) {
                return;
            }
            this.hyperlink = findHyperlink(element);
        }

        createClass(Link, [{
            key: 'toJSON',
            value: function toJSON() {
                if (!this.hyperlink) {
                    return;
                }
                return {
                    name: this.hyperlink.innerText,
                    href: this.hyperlink.getAttribute('href')
                };
            }
        }]);
        return Link;
    }();

    function render(html, data) {
        var template = ['<div class="pagination">', '<div>', data.prev && '&larr; <a href="' + data.prev.href + '">' + data.prev.name + '</a>', '</div>', '<div>', data.next && '<a href="' + data.next.href + '">' + data.next.name + '</a> &rarr;', '</div>', '</div>'].filter(Boolean).join('');
        return html + template;
    }

    function css() {
        var template = ['.pagination {', 'padding: 1em 0;', 'display: flex;', 'justify-content: space-between;', '}'].join('');

        return insertCss_1(template);
    }

    $docsify.plugins = [].concat(install, $docsify.plugins);

})));